package cn.stylefeng.guns.cloud.workflow.modular.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.guns.cloud.libs.context.auth.LoginContext;
import cn.stylefeng.guns.cloud.libs.mp.page.PageFactory;
import cn.stylefeng.guns.cloud.model.page.PageResult;
import cn.stylefeng.guns.cloud.system.api.model.UserInfo;
import cn.stylefeng.guns.cloud.system.api.model.WorkflowRoleInfo;
import cn.stylefeng.guns.cloud.system.api.model.req.UserByRoleReq;
import cn.stylefeng.guns.cloud.system.api.model.req.UserListReq;
import cn.stylefeng.guns.cloud.workflow.api.entity.ActBaseEntity;
import cn.stylefeng.guns.cloud.workflow.api.model.result.ActBaseResult;
import cn.stylefeng.guns.cloud.workflow.modular.consumer.SystemConsumer;
import cn.stylefeng.guns.cloud.workflow.modular.service.ActBaseService;
import cn.stylefeng.guns.cloud.workflow.modular.service.ApproveHistoryService;
import cn.stylefeng.guns.cloud.workflow.modular.service.TodoTaskService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 流程基础 服务实现类
 *
 * @Author xuyuxiang
 * @Date 2019/11/18 11:15
 **/
@Service
public class ActBaseServiceImpl implements ActBaseService {

    @Autowired
    private IdentityService identityService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private ApproveHistoryService approveHistoryService;

    @Autowired
    private TodoTaskService todoTaskService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private SystemConsumer systemConsumer;

    @Override
    public void start(String processDefinitionKey, Long businessId, ActBaseEntity entity, Map paramMap) {
        //当前登录用户id
        Long applyUserId = LoginContext.me().getAccountId();

        //获取当前登录用户姓名
        String applyUserName = LoginContext.me().getLoginUser().getName();

        //填充申请人id
        entity.setApplyUserId(applyUserId);

        //填充申请时间
        entity.setApplyDate(DateUtil.now());

        //保存启动流程参数【默认将整个实体存入变量，方便条件流转的判断】
        paramMap.put("entity", entity);

        //默认将申请人作为固定参数传入，方便以后获取申请人
        paramMap.put("applyUserId", applyUserId);

        //默认将申请人姓名作为固定参数传入，方便以后获取申请人姓名
        paramMap.put("applyUserName", applyUserName);

        //默认将申请时间作为固定参数传入，方便以后获取申请时间
        paramMap.put("applyDate", DateUtil.now());

        //保存发起人信息，会在act_ru_identitylink表的starter的这一条记录中保存user_id，方便以后查看发起人的id，
        identityService.setAuthenticatedUserId(String.valueOf(applyUserId));

        //map存储变量 用流程定义的KEY启动，会自动选择KEY相同的流程定义中最新版本的那个(KEY为模型中的流程唯一标识)
        //将业务表id作为businessKey传入，用于后续根据businessKey判断表单地址
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, String.valueOf(businessId), paramMap);

        //获取流程实例id
        String processInstanceId = processInstance.getId();

        //填充申请信息
        approveHistoryService.saveStartEventApproveInfo(processInstanceId);
        //返回流程实例ID
        entity.setProcessInstanceId(processInstanceId);
    }

    @Override
    public void reStart(ActBaseEntity entity) {
        todoTaskService.reStartOrCancelRequire(entity, 3);
    }

    @Override
    public void cancel(ActBaseEntity entity) {
        todoTaskService.reStartOrCancelRequire(entity, 4);
    }

    @Override
    public void fillEntityList(List<ActBaseEntity> entityList) {
        for (ActBaseEntity actBaseEntity : entityList) {
            this.fillEntity(actBaseEntity);
        }
    }

    @Override
    public void fillResultList(List<ActBaseResult> resultList) {
        for (ActBaseResult actBaseResult : resultList) {
            this.fillResult(actBaseResult);
        }
    }

    @Override
    public void fillEntityPage(PageResult pageResult) {
        List pageResultRows = pageResult.getRows();
        this.fillEntityList(pageResultRows);
    }

    @Override
    public void fillResultPage(PageResult pageResult) {
        List pageResultRows = pageResult.getRows();
        this.fillResultList(pageResultRows);
    }

    public void fillEntity(ActBaseEntity entity) {

        String processInstanceId = entity.getProcessInstanceId();
        if (ObjectUtil.isEmpty(processInstanceId)) {
            entity.setApplyUserName("-");
            entity.setApplyDate("-");
            entity.setApproveProcess("-");
            entity.setApproveUserName("-");
            entity.setApproveStatus(0);

        } else {
            Long applyUserId = entity.getApplyUserId();

            String applyUserName = this.getNameByUserId(applyUserId);

            entity.setApplyUserName(applyUserName);
            //获取实例
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(processInstanceId).singleResult();
            //运行中
            if (ObjectUtil.isNotEmpty(processInstance)) {

                Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();

                //当前审批环节
                String taskName = task.getName();

                //当前审批人
                String taskAssignee = task.getAssignee();

                //待办人姓名
                String taskAssigneeUserName = "-";

                //待办人不存在，表示该任务为组任务,则不展示待办人姓名,只有待办人为具体人员时才展示
                if (ObjectUtil.isNotEmpty(taskAssignee)) {
                    //待办人姓名
                    taskAssigneeUserName = this.getNameByUserId(taskAssignee);
                }

                //当前审批状态
                entity.setApproveProcess(taskName);
                entity.setApproveUserName(taskAssigneeUserName);
                entity.setApproveStatus(1);
            } else {//已结束
                entity.setApproveProcess("-");
                entity.setApproveUserName("-");
                entity.setApproveStatus(2);
            }
        }
    }

    public void fillResult(ActBaseResult result) {

        String processInstanceId = result.getProcessInstanceId();
        if (ObjectUtil.isEmpty(processInstanceId)) {
            result.setApplyUserName("-");
            result.setApplyDate("-");
            result.setApproveProcess("-");
            result.setApproveUserName("-");
            result.setApproveStatus(0);

        } else {
            Long applyUserId = result.getApplyUserId();

            String applyUserName = this.getNameByUserId(applyUserId);

            result.setApplyUserName(applyUserName);
            //获取实例
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(processInstanceId).singleResult();
            //运行中
            if (ObjectUtil.isNotEmpty(processInstance)) {

                Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();

                //当前审批环节
                String taskName = task.getName();

                //当前审批人
                String taskAssignee = task.getAssignee();

                //待办人姓名
                String taskAssigneeUserName = "-";

                //待办人不存在，表示该任务为组任务,则不展示待办人姓名,只有待办人为具体人员时才展示
                if (ObjectUtil.isNotEmpty(taskAssignee)) {
                    //待办人姓名
                    taskAssigneeUserName = this.getNameByUserId(taskAssignee);
                }

                //当前审批状态
                result.setApproveProcess(taskName);
                result.setApproveUserName(taskAssigneeUserName);
                result.setApproveStatus(1);
            } else {//已结束
                result.setApproveProcess("-");
                result.setApproveUserName("-");
                result.setApproveStatus(2);
            }
        }
    }

    /**
     * 根据用户id（Long)获取用户名，远程调用system接口
     *
     * @Author xuyuxiang
     * @Date 2019/11/19 14:29
     **/
    @Override
    public String getNameByUserId(Long userId) {
        return systemConsumer.getNameByAccountId(userId);
    }

    /**
     * 根据用户id（String)获取用户名，远程调用system接口
     * 方便用户id为String类型的其他方法调用
     *
     * @Author xuyuxiang
     * @Date 2019/11/19 14:29
     **/
    @Override
    public String getNameByUserId(String userId) {
        return this.getNameByUserId(Long.valueOf(userId));
    }

    /**
     * 获取候选人列表，远程调用system接口
     *
     * @Author xuyuxiang
     * @Date 2019/11/19 14:39
     **/
    @Override
    public List<UserInfo> getCandidateUser(Set<Long> candidateUserIdSet, Set<Long> candidateGroupIdSet) {

        UserListReq userListReq = new UserListReq();
        userListReq.setAccountIds(candidateUserIdSet);
        userListReq.setRoleIds(candidateGroupIdSet);

        return systemConsumer.getUserListByUserIdsOrRoleIds(userListReq);
    }

    /**
     * 获取角色列表，远程调用system接口
     *
     * @Author xuyuxiang
     * @Date 2019/11/19 14:50
     **/
    @Override
    public List<WorkflowRoleInfo> getRoleList() {
        return systemConsumer.getRoleList();
    }

    /**
     * 获取角色下用户列表，远程调用system接口
     *
     * @Author xuyuxiang
     * @Date 2019/11/19 14:50
     **/
    @Override
    public Page<UserInfo> getUserListByRoleId(Long roleId) {
        UserByRoleReq userByRoleReq = new UserByRoleReq();
        userByRoleReq.setRoleId(roleId);
        userByRoleReq.setPage(this.getPageContext());
        return systemConsumer.getUsersByRoleIdByPage(userByRoleReq);
    }

    private Page getPageContext() {
        return PageFactory.defaultPage();
    }
}
